#pragma once
#include<iostream>
#include<vector>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<string>
#include<cstring>
#include"Task.hpp"
class channel{
public:
    channel(int wfd,pid_t subid):_wfd(wfd),_subid(subid){
        _name="channel-"+std::to_string(_wfd)+"-"+std::to_string(_subid);
    }
    ~channel(){}
    int get_wfd(){
        return _wfd;
    }
    int get_subid(){
        return _subid;
    }
    std::string get_name(){
        return _name;
    }
    void Send(int code){
        int n=write(_wfd,&code,sizeof(code));
        if(n<0){
        std::cout<<"error: "<<strerror(errno)<<std::endl;
        }
    }
    void Close(){
        close(_wfd);
        std::cout<<"信道关闭"<<std::endl;
    }
    void Wait(){
        pid_t pid=waitpid(_subid,nullptr,0);
        (void)pid;
    }
private:
    int _wfd;//管道读的fd
    pid_t _subid;//子进程id
    std::string _name;

};
class channelManager{
public:
    channelManager():_next(0){}
    ~channelManager(){}
    void Insert(int wfd,pid_t subid){
        // channel c(wfd,subid);
        // _channels.push_back(c);
        _channels.emplace_back(wfd,subid);
    }
    channel& Select(){
        //简单的负载均衡，选择第一个信道
        auto &c = _channels[_next];
        _next++;
        _next %= _channels.size();
        return c;
    }
    void PrintChannel(){
        for(auto& c : _channels){
            std::cout<<c.get_name()<<" "<<c.get_wfd()<<" "<<c.get_subid()<<std::endl;
        }
    }
    void stopsubprocess(){
        for (size_t i = 0; i < _channels.size(); i++)
        {
            _channels[i].Close();
            std::cout<<"关闭子进程"<<_channels[i].get_name()<<std::endl;
        }
    }
    void waitsubprocess(){
        for(auto& c : _channels){
           c.Wait();
           std::cout<<"回收子进程"<<c.get_name()<<std::endl;
        }
    }
    private:
    std::vector<channel> _channels;
    int _next;
};
const int gdefaultnum=5;
class processPool{
    public:
    processPool(int num=gdefaultnum):_process_num(num){
        _tm.Register(Printlog);
        _tm.Register(DownLoad);
        _tm.Register(Upload);
        _tm.Register(Delete);
        _tm.Register(Compress);
    }
    ~processPool(){}
    void Work(int rfd){
        while(true){
           int code=0;//一次读取四个字节
           ssize_t n=read(rfd,&code,sizeof(code));
           if(n>0){
                if(n!=sizeof(code)){
                    continue;
                }
                std::cout<<"子进程"<<getpid()<<"收到任务码"<<code<<std::endl;
                _tm.Execute(code);
              }
              else if(n==0){//写端关闭
                std::cout<<"子进程"<<getpid()<<"退出"<<std::endl;
                break;
              }
              else{//读失败
                std::cerr<<"读取错误"<<std::endl;
                break;
           }
        }
    }
    bool Create(){
        for(int i=0;i<_process_num;i++){
            //创建管道
            int pipefd[2]={0};
            if(pipe(pipefd)<0){
                std::cerr<<"create pipe error"<<std::endl;
                return false;
            }
            //创建子进程
            pid_t subid=fork();
            if(subid<0){
                std::cerr<<"fork error"<<std::endl;
                return false;
            }
            else if(subid==0){
                //子进程
                //关闭不需要的文件描述符
                close(pipefd[1]);///0读1写
                Work(pipefd[0]);
                close(pipefd[0]);
                exit(0);
            }
            else{
                close(pipefd[0]);
                _cm.Insert(pipefd[1],subid);
            }
        }
        return true;
    }
    void Run(){
        //选择一个任务
        int cnt=0;
        while(true){
        if(cnt++>10){
            std::cout<<"主进程退出"<<std::endl;
            stop();
            break;
        }
        int taskcode=_tm.Code();
        //选择一个信道，负载均衡式
        channel &c=_cm.Select();
        std::cout<<"主进程选择信道："<<c.get_name()<<"发送任务码："<<taskcode<<std::endl;
        //发送任务
        c.Send(taskcode);
        std::cout<<"主进程发送了一个任务："<<taskcode<<std::endl;
        sleep(1);
        }
    }
    void stop(){
        _cm.stopsubprocess(); //关闭所有信道
        _cm.waitsubprocess(); //等待所有子进程回收
    }
    void Debug(){
        _cm.PrintChannel();
    }
    private:
    channelManager _cm;
    int _process_num;//进程个数
    TaskMannager _tm;
};
